<template>
  <div class="crud-wrapper">
    <!--头部-->
    <el-space class="crud-header">
      <slot name="header-left"></slot>
      <el-input class="filter-item" v-model="query.keyword" :placeholder="setting.searchPlaceholder" />
      <el-button type="success" :icon="Search" @click="handleSearch">{{ setting.searchText }}</el-button>
      <slot name="header-right"></slot>
    </el-space>
    <!--工具栏-->
    <el-row class="crud-tools" justify="space-between">
      <el-col :span="12">
        <el-button v-if="setting.add" class="filter-item" type="primary" :icon="Plus" @click="toAdd" :disabled="!!selection.length">{{
          setting.addText
        }}</el-button>
        <el-button v-if="setting.edit" class="filter-item" type="success" :icon="EditPen" @click="toEdit">{{
          setting.editText
        }}</el-button>
        <el-button v-if="setting.del" class="filter-item" type="danger" :icon="Delete" @click="toDel" :disabled="!selection.length">{{
          setting.delText
        }}</el-button>
        <el-button v-if="setting.exp" class="filter-item" type="warning" :icon="Files" @click="toExp" :disabled="!selection.length">{{
          setting.expText
        }}</el-button>
      </el-col>
      <el-col :span="12">
        <el-row justify="end">
          <el-radio-group style="margin-bottom: 30px">
            <el-tooltip effect="dark" content="刷新" placement="top">
              <el-button plain type="info" :icon="Refresh" @click="refresh" />
            </el-tooltip>
            <el-tooltip effect="dark" content="下载数据" placement="top">
              <el-button plain type="info" :icon="Download" @click="download" />
            </el-tooltip>
            <el-popover placement="bottom-end" width="150" trigger="click">
              <template #reference>
                <el-button plain type="info" :icon="Setting" />
              </template>
              <el-checkbox-group v-model="checkedColumns" @change="handleCheckedColumnsChange">
                <el-scrollbar class='crud-popover' height='250px'>
                  <el-checkbox v-for="(item, index) in cloneColumn" :label="item" :key="index">
                    <div class='crud-checkbox-item'>{{ item }}</div>
                  </el-checkbox>
                </el-scrollbar>
              </el-checkbox-group>
            </el-popover>
          </el-radio-group>
        </el-row>
      </el-col>
    </el-row>
    <!-- 表格主体 -->
    <el-table id="curd-table" ref="tableEl" class="crud-table" :data="data" v-loading="loading"
      @selection-change="selectionChange" header-row-class-name="crud-table-header">
      <template v-for="(item, index) in column" :key="index">
        <el-table-column v-if="item.slotName" v-bind="item">
          <template v-slot:default="{ row, column, $index }">
            <slot :name="item.slotName" :$index="$index" :row="row" :column="column" />
          </template>
        </el-table-column>
        <el-table-column v-else v-bind="item" />
      </template>
    </el-table>
    <!--分页-->
    <el-row class="crud-pagination" justify="end">
      <el-pagination background v-model:page-size="query.size" :total="pTotal" v-model:current-page="query.pagination"
        :pager-count="5" layout="total, sizes, prev, pager, next, jumper" @size-change="sizeChange"
        @current-change="currentChange" />
    </el-row>
  </div>
</template>

<script setup lang="ts" name="crud3-index">
import { Search, Refresh, Download, Plus, EditPen, Delete, Files, Setting } from '@element-plus/icons-vue'
import * as XLSX from 'xlsx'
import FileSaver from "file-saver"
import { ElMessage } from 'element-plus'

interface tableDataTypes {
  data: Array<{}>
  column: Array<any>
  query: any
  api: Function,
  setting?: any
}

interface Props {
  tableData: tableDataTypes
}

const props = withDefaults(defineProps<Props>(), {})

const { data, column, query } = toRefs(props.tableData)
const { api } = props.tableData

const pTotal = ref(0)
const loading = ref(true)
const tableEl = ref()

const attrs = useAttrs()

//column添加默认属性
column.value.map((item: any) => {
  if (item.label) {
    item.show = true
  }
  if (!item.hasOwnProperty('align')) {
    item.align = 'center'
  }
})

//setting默认
const setting = Object.assign({
  searchPlaceholder: '模糊搜索',
  searchText: '搜索',
  add: true,
  addText: '新增',
  edit: false,
  editText: '编辑',
  del: false,
  delText: '删除',
  exp: false,
  expText: '导出',

}, props.tableData.setting)

//多选
const selection = ref([])
const selectionChange = (val: any) => {
  selection.value = val
}

const getList = async () => {
  loading.value = true
  setTimeout(() => { loading.value = false }, 800)
  const res = await api(query.value)
  const { items, pagination, size, total } = res.data
  data.value = items
  query.value.pagination = pagination
  query.value.size = size
  pTotal.value = total
}

onMounted(() => {
  getList()
})

//头部-搜索
const handleSearch = () => {
  getList()
}
//工具栏-默认-刷新
const refresh = () => {
  query.value.pagination = 1
  getList()
}
//分页-当前页改变
const currentChange = (value: number) => {
  query.value.pagination = value
  getList()
}
//分页-每页条数改变
const sizeChange = (value: number) => {
  query.value.size = value
  currentChange(1)
}

const emits = defineEmits(['onToAdd', 'onToEdit', 'onToDel', 'onToExp']);
//工具栏-新增
const toAdd = () => {
  emits('onToAdd')
}

//工具栏-修改
function toEdit() {
  emits('onToEdit', selection.value)
}

//工具栏-删除
const toDel = () => {
  emits('onToDel', selection.value)
}

//工具栏-导出
const toExp = () => {
  emits('onToExp', selection.value)
}

//下载表格
const download = () => {
  const xlsxParam = { raw: true };
  const wb = XLSX.utils.table_to_book(document.querySelector('#curd-table'), xlsxParam);
  const wbOut = XLSX.write(wb, {
    bookType: 'xlsx',
    bookSST: true,
    type: 'array',
  });
  try {
    FileSaver.saveAs(new Blob([wbOut], { type: 'application/octet-stream' }), "download.xlsx");
  } catch (e) {
    if (typeof console !== 'undefined') {
      ElMessage.error('下载失败')
    }
  }
  return wbOut;
}

const checkedColumns = ref([])
const handleCheckedColumnsChange = () => {
  updateColumns(checkedColumns.value)
}
//初始化checkedColumns状态
let cloneColumn = column.value.filter(item => item.label).map((item: any) => {
  if (item.show) {
    return item.label
  }
})
checkedColumns.value = (cloneColumn.filter(item => item) as any)

const defaultColumn = column.value.filter(item => item)

const updateColumns = (newColumns: any) => {
  loading.value = true
  column.value = defaultColumn.filter(item => {
    if (item.label) {
      if (newColumns.includes(item.label)) {
        return item
      }
    } else {
      return item
    }
  })
  //重载table
  getList()
}

//对外暴露方法
defineExpose({
  tableEl,
  refresh
})
</script>

<style lang="scss" scoped>
.crud-wrapper {
  width: 100%;

  .crud-tools {
    margin-bottom: 22px;
  }

  .crud-table {
    width: 100%;

    :deep(.crud-table-header) th {
      background-color: #f7f8fa;
      border-bottom: none;
    }
  }

  .filter-item {
    margin-right: 8px;
    margin-left: 0;
  }

  .crud-header {
    margin-bottom: 22px;
  }

  :deep(.el-radio-group) {
    margin-bottom: 0 !important;

    .el-button {
      margin-left: -1px;
      background-color: #fff;

      &:focus,
      &:hover {
        color: #ffffff;
        border-color: #909399;
        background-color: #909399;
      }
    }

    .el-button:not(:first-child):not(:last-child) {
      border-radius: 0;
    }

    .el-button:first-child {
      border-top-right-radius: 0;
      border-bottom-right-radius: 0;
    }

    .el-button:last-child {
      border-top-left-radius: 0;
      border-bottom-left-radius: 0;
    }
  }

  .crud-pagination {
    margin-top: 30px;
  }

  .crud-popover {
    width: 100%;
  }

  .crud-checkbox-item {
    max-width: 70px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}
</style>